home *** CD-ROM | disk | FTP | other *** search
- Path: abcfd20.larc.nasa.gov!amiga-request
- From: amiga-request@abcfd20.larc.nasa.gov (Amiga Sources/Binaries Moderator)
- Subject: v90i255: DKBTrace 2.01 - DKBtrace Ray-Tracer, Part07/10
- Reply-To: David Schanen <mtv@milton.u.washington.edu>
- Newsgroups: comp.sources.amiga
- Message-ID: <comp.sources.amiga:v90i255@abcfd20.larc.nasa.gov>
- References: <comp.sources.amiga:v90i249@abcfd20.larc.nasa.gov>
- Date: 03 Sep 90 23:22:24 GMT
- Approved: tadguy@uunet.UU.NET (Tad Guy)
- X-Mail-Submissions-To: amiga@uunet.uu.net
- X-Post-Discussions-To: comp.sys.amiga
-
- Submitted-by: David Schanen <mtv@milton.u.washington.edu>
- Posting-number: Volume 90, Issue 255
- Archive-name: applications/dkbtrace-2.01/part07
-
- #!/bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 7 (of 10)."
- # Contents: src/iff.h src/lighting.c
- # Wrapped by tadguy@abcfd20 on Mon Sep 3 19:21:21 1990
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'src/iff.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'src/iff.h'\"
- else
- echo shar: Extracting \"'src/iff.h'\" \(20481 characters\)
- sed "s/^X//" >'src/iff.h' <<'END_OF_FILE'
- X#ifndef IFF_H
- X#define IFF_H
- X/*----------------------------------------------------------------------*/
- X/* IFF.H defs for IFF-85 Interchange Format Files. 1/22/86 */
- X/* */
- X/* By Jerry Morrison and Steve Shaw, Electronic Arts. */
- X/* This software is in the public domain. */
- X/*----------------------------------------------------------------------*/
- X
- X#ifndef COMPILER_H
- X#include "iff/compiler.h"
- X#endif
- X
- X#ifndef LIBRARIES_DOS_H
- X#include "libraries/dos.h"
- X#endif
- X
- X#ifndef OFFSET_BEGINNING
- X#define OFFSET_BEGINNING OFFSET_BEGINING
- X#endif
- X
- Xtypedef LONG IFFP; /* Status code result from an IFF procedure */
- X /* LONG, because must be type compatable with ID for GetChunkHdr.*/
- X /* Note that the error codes below are not legal IDs.*/
- X#define IFF_OKAY 0L /* Keep going...*/
- X#define END_MARK -1L /* As if there was a chunk at end of group.*/
- X#define IFF_DONE -2L /* clientProc returns this when it has READ enough.
- X * It means return thru all levels. File is Okay.*/
- X#define DOS_ERROR -3L
- X#define NOT_IFF -4L /* not an IFF file.*/
- X#define NO_FILE -5L /* Tried to open file, DOS didn't find it.*/
- X#define CLIENT_ERROR -6L /* Client made invalid request, for instance, write
- X * a negative size chunk.*/
- X#define BAD_FORM -7L /* A client read proc complains about FORM semantics;
- X * e.g. valid IFF, but missing a required chunk.*/
- X#define SHORT_CHUNK -8L /* Client asked to IFFReadBytes more bytes than left
- X * in the chunk. Could be client bug or bad form.*/
- X#define BAD_IFF -9L /* mal-formed IFF file. [TBD] Expand this into a
- X * range of error codes.*/
- X#define LAST_ERROR BAD_IFF
- X
- X/* This MACRO is used to RETURN immediately when a termination condition is
- X * found. This is a pretty weird macro. It requires the caller to declare a
- X * local "IFFP iffp" and assign it. This wouldn't work as a subroutine since
- X * it returns for it's caller. */
- X#define CheckIFFP() { if (iffp != IFF_OKAY) return(iffp); }
- X
- X
- X/* ---------- ID -------------------------------------------------------*/
- X
- Xtypedef LONG ID; /* An ID is four printable ASCII chars but
- X * stored as a LONG for efficient copy & compare.*/
- X
- X/* Four-character IDentifier builder.*/
- X#define MakeID(a,b,c,d) ( (LONG)(a)<<24L | (LONG)(b)<<16L | (c)<<8 | (d) )
- X
- X/* Standard group IDs. A chunk with one of these IDs contains a
- X SubTypeID followed by zero or more chunks.*/
- X#define FORM MakeID('F','O','R','M')
- X#define PROP MakeID('P','R','O','P')
- X#define LIST MakeID('L','I','S','T')
- X#define CAT MakeID('C','A','T',' ')
- X#define FILLER MakeID(' ',' ',' ',' ')
- X/* The IDs "FOR1".."FOR9", "LIS1".."LIS9", & "CAT1".."CAT9" are reserved
- X * for future standardization.*/
- X
- X/* Pseudo-ID used internally by chunk reader and writer.*/
- X#define NULL_CHUNK 0L /* No current chunk.*/
- X
- X
- X/* ---------- Chunk ----------------------------------------------------*/
- X
- X/* All chunks start with a type ID and a count of the data bytes that
- X follow--the chunk's "logicl size" or "data size". If that number is odd,
- X a 0 pad byte is written, too. */
- Xtypedef struct {
- X ID ckID;
- X LONG ckSize;
- X } ChunkHeader;
- X
- Xtypedef struct {
- X ID ckID;
- X LONG ckSize;
- X UBYTE ckData[ 1 /*REALLY: ckSize*/ ];
- X } Chunk;
- X
- X/* Pass ckSize = szNotYetKnown to the writer to mean "compute the size".*/
- X#define szNotYetKnown 0x80000001L
- X
- X/* Need to know whether a value is odd so can word-align.*/
- X#define IS_ODD(a) ((a) & 1)
- X
- X/* This macro rounds up to an even number. */
- X#define WordAlign(size) ((size+1)&~1)
- X
- X/* ALL CHUNKS MUST BE PADDED TO EVEN NUMBER OF BYTES.
- X * ChunkPSize computes the total "physical size" of a padded chunk from
- X * its "data size" or "logical size". */
- X#define ChunkPSize(dataSize) (WordAlign(dataSize) + sizeof(ChunkHeader))
- X
- X/* The Grouping chunks (LIST, FORM, PROP, & CAT) contain concatenations of
- X * chunks after a subtype ID that identifies the content chunks.
- X * "FORM type XXXX", "LIST of FORM type XXXX", "PROPerties associated
- X * with FORM type XXXX", or "conCATenation of XXXX".*/
- Xtypedef struct {
- X ID ckID;
- X LONG ckSize; /* this ckSize includes "grpSubID".*/
- X ID grpSubID;
- X } GroupHeader;
- X
- Xtypedef struct {
- X ID ckID;
- X LONG ckSize;
- X ID grpSubID;
- X UBYTE grpData[ 1 /*REALLY: ckSize-sizeof(grpSubID)*/ ];
- X } GroupChunk;
- X
- X
- X/* ---------- IFF Reader -----------------------------------------------*/
- X
- X/******** Routines to support a stream-oriented IFF file reader *******
- X *
- X * These routines handle lots of details like error checking and skipping
- X * over padding. They're also careful not to read past any containing context.
- X *
- X * These routines ASSUME they're the only ones reading from the file.
- X * Client should check IFFP error codes. Don't press on after an error!
- X * These routines try to have no side effects in the error case, except
- X * partial I/O is sometimes unavoidable.
- X *
- X * All of these routines may return DOS_ERROR. In that case, ask DOS for the
- X * specific error code.
- X *
- X * The overall scheme for the low level chunk reader is to open a "group read
- X * context" with OpenRIFF or OpenRGroup, read the chunks with GetChunkHdr
- X * (and its kin) and IFFReadBytes, and close the context with CloseRGroup.
- X *
- X * The overall scheme for reading an IFF file is to use ReadIFF, ReadIList,
- X * and ReadICat to scan the file. See those procedures, ClientProc (below),
- X * and the skeleton IFF reader. */
- X
- X/* Client passes ptrs to procedures of this type to ReadIFF which call them
- X * back to handle LISTs, FORMs, CATs, and PROPs.
- X *
- X * Use the GroupContext ptr when calling reader routines like GetChunkHdr.
- X * Look inside the GroupContext ptr for your ClientFrame ptr. You'll
- X * want to type cast it into a ptr to your containing struct to get your
- X * private contextual data (stacked property settings). See below. */
- X#ifdef FDwAT
- Xtypedef IFFP ClientProc(struct _GroupContext *);
- X#else
- Xtypedef IFFP ClientProc();
- X#endif
- X
- X/* Client's context for reading an IFF file or a group.
- X * Client should actually make this the first component of a larger struct
- X * (it's personal stack "frame") that has a field to store each "interesting"
- X * property encountered.
- X * Either initialize each such field to a global default or keep a boolean
- X * indicating if you've read a property chunk into that field.
- X * Your getList and getForm procs should allocate a new "frame" and copy the
- X * parent frame's contents. The getProp procedure should store into the frame
- X * allocated by getList for the containing LIST. */
- Xtypedef struct _ClientFrame {
- X ClientProc *getList, *getProp, *getForm, *getCat;
- X /* client's own data follows; place to stack property settings */
- X } ClientFrame;
- X
- X/* Our context for reading a group chunk. */
- Xtypedef struct _GroupContext {
- X struct _GroupContext *parent; /* Containing group; NULL => whole file. */
- X ClientFrame *clientFrame; /* Reader data & client's context state. */
- X BPTR file; /* Byte-stream file handle. */
- X LONG position; /* The context's logical file position. */
- X LONG bound; /* File-absolute context bound
- X * or szNotYetKnown (writer only). */
- X ChunkHeader ckHdr; /* Current chunk header. ckHdr.ckSize = szNotYetKnown
- X * means we need to go back and set the size (writer only).
- X * See also Pseudo-IDs, above. */
- X ID subtype; /* Group's subtype ID when reading. */
- X LONG bytesSoFar; /* # bytes read/written of current chunk's data. */
- X } GroupContext;
- X
- X/* Computes the number of bytes not yet read from the current chunk, given
- X * a group read context gc. */
- X#define ChunkMoreBytes(gc) ((gc)->ckHdr.ckSize - (gc)->bytesSoFar)
- X
- X
- X/***** Low Level IFF Chunk Reader *****/
- X
- X#ifdef FDwAT
- X
- X/* Given an open file, open a read context spanning the whole file.
- X * This is normally only called by ReadIFF.
- X * This sets new->clientFrame = clientFrame.
- X * ASSUME context allocated by caller but not initialized.
- X * ASSUME caller doesn't deallocate the context before calling CloseRGroup.
- X * NOT_IFF ERROR if the file is too short for even a chunk header.*/
- Xextern IFFP OpenRIFF(BPTR, GroupContext *, ClientFrame *);
- X /* file, new, clientFrame */
- X
- X/* Open the remainder of the current chunk as a group read context.
- X * This will be called just after the group's subtype ID has been read
- X * (automatically by GetChunkHdr for LIST, FORM, PROP, and CAT) so the
- X * remainder is a sequence of chunks.
- X * This sets new->clientFrame = parent->clientFrame. The caller should repoint
- X * it at a new clientFrame if opening a LIST context so it'll have a "stack
- X * frame" to store PROPs for the LIST. (It's usually convenient to also
- X * allocate a new Frame when you encounter FORM of the right type.)
- X *
- X * ASSUME new context allocated by caller but not initialized.
- X * ASSUME caller doesn't deallocate the context or access the parent context
- X * before calling CloseRGroup.
- X * BAD_IFF ERROR if context end is odd or extends past parent. */
- Xextern IFFP OpenRGroup(GroupContext *, GroupContext *);
- X /* parent, new */
- X
- X/* Close a group read context, updating its parent context.
- X * After calling this, the old context may be deallocated and the parent
- X * context can be accessed again. It's okay to call this particular procedure
- X * after an error has occurred reading the group.
- X * This always returns IFF_OKAY. */
- Xextern IFFP CloseRGroup(GroupContext *);
- X /* old */
- X
- X/* Skip any remaining bytes of the previous chunk and any padding, then
- X * read the next chunk header into context.ckHdr.
- X * If the ckID is LIST, FORM, CAT, or PROP, this automatically reads the
- X * subtype ID into context->subtype.
- X * Caller should dispatch on ckID (and subtype) to an appropriate handler.
- X *
- X * RETURNS context.ckHdr.ckID (the ID of the new chunk header); END_MARK
- X * if there are no more chunks in this context; or NOT_IFF if the top level
- X * file chunk isn't a FORM, LIST, or CAT; or BAD_IFF if malformed chunk, e.g.
- X * ckSize is negative or too big for containing context, ckID isn't positive,
- X * or we hit end-of-file.
- X *
- X * See also GetFChunkHdr, GetF1ChunkHdr, and GetPChunkHdr, below.*/
- Xextern ID GetChunkHdr(GroupContext *);
- X /* context.ckHdr.ckID context */
- X
- X/* Read nBytes number of data bytes of current chunk. (Use OpenGroup, etc.
- X * instead to read the contents of a group chunk.) You can call this several
- X * times to read the data piecemeal.
- X * CLIENT_ERROR if nBytes < 0. SHORT_CHUNK if nBytes > ChunkMoreBytes(context)
- X * which could be due to a client bug or a chunk that's shorter than it
- X * ought to be (bad form). (on either CLIENT_ERROR or SHORT_CHUNK,
- X * IFFReadBytes won't read any bytes.) */
- Xextern IFFP IFFReadBytes(GroupContext *, BYTE *, LONG);
- X /* context, buffer, nBytes */
- X
- X
- X/***** IFF File Reader *****/
- X
- X/* This is a noop ClientProc that you can use for a getList, getForm, getProp,
- X * or getCat procedure that just skips the group. A simple reader might just
- X * implement getForm, store ReadICat in the getCat field of clientFrame, and
- X * use SkipGroup for the getList and getProp procs.*/
- Xextern IFFP SkipGroup(GroupContext *);
- X
- X/* IFF file reader.
- X * Given an open file, allocate a group context and use it to read the FORM,
- X * LIST, or CAT and it's contents. The idea is to parse the file's contents,
- X * and for each FORM, LIST, CAT, or PROP encountered, call the getForm,
- X * getList, getCat, or getProp procedure in clientFrame, passing the
- X * GroupContext ptr.
- X * This is achieved with the aid of ReadIList (which your getList should
- X * call) and ReadICat (which your getCat should call, if you don't just use
- X * ReadICat for your getCat). If you want to handle FORMs, LISTs, and CATs
- X * nested within FORMs, the getForm procedure must dispatch to getForm,
- X * getList, and getCat (it can use GetF1ChunkHdr to make this easy).
- X *
- X * Normal return is IFF_OKAY (if whole file scanned) or IFF_DONE (if a client
- X * proc said "done" first).
- X * See the skeletal getList, getForm, getCat, and getProp procedures. */
- Xextern IFFP ReadIFF(BPTR, ClientFrame *);
- X /* file, clientFrame */
- X
- X/* IFF LIST reader.
- X * Your "getList" procedure should allocate a ClientFrame, copy the parent's
- X * ClientFrame, and then call this procedure to do all the work.
- X *
- X * Normal return is IFF_OKAY (if whole LIST scanned) or IFF_DONE (if a client
- X * proc said "done" first).
- X * BAD_IFF ERROR if a PROP appears after a non-PROP. */
- Xextern IFFP ReadIList(GroupContext *, ClientFrame *);
- X /* parent, clientFrame */
- X
- X/* IFF CAT reader.
- X * Most clients can simply use this to read their CATs. If you must do extra
- X * setup work, put a ptr to your getCat procedure in the clientFrame, and
- X * have that procedure call ReadICat to do the detail work.
- X *
- X * Normal return is IFF_OKAY (if whole CAT scanned) or IFF_DONE (if a client
- X * proc said "done" first).
- X * BAD_IFF ERROR if a PROP appears in the CAT. */
- Xextern IFFP ReadICat(GroupContext *);
- X /* parent */
- X
- X/* Call GetFChunkHdr instead of GetChunkHdr to read each chunk inside a FORM.
- X * It just calls GetChunkHdr and returns BAD_IFF if it gets a PROP chunk. */
- Xextern ID GetFChunkHdr(GroupContext *);
- X /* context.ckHdr.ckID context */
- X
- X/* GetF1ChunkHdr is like GetFChunkHdr, but it automatically dispatches to the
- X * getForm, getList, and getCat procedure (and returns the result) if it
- X * encounters a FORM, LIST, or CAT. */
- Xextern ID GetF1ChunkHdr(GroupContext *);
- X /* context.ckHdr.ckID context */
- X
- X/* Call GetPChunkHdr instead of GetChunkHdr to read each chunk inside a PROP.
- X * It just calls GetChunkHdr and returns BAD_IFF if it gets a group chunk. */
- Xextern ID GetPChunkHdr(GroupContext *);
- X /* context.ckHdr.ckID context */
- X
- X#else /* not FDwAT */
- X
- Xextern IFFP OpenRIFF();
- Xextern IFFP OpenRGroup();
- Xextern IFFP CloseRGroup();
- Xextern ID GetChunkHdr();
- Xextern IFFP IFFReadBytes();
- Xextern IFFP SkipGroup();
- Xextern IFFP ReadIFF();
- Xextern IFFP ReadIList();
- Xextern IFFP ReadICat();
- Xextern ID GetFChunkHdr();
- Xextern ID GetF1ChunkHdr();
- Xextern ID GetPChunkHdr();
- X
- X#endif /* not FDwAT */
- X
- X/* ---------- IFF Writer -----------------------------------------------*/
- X
- X/******* Routines to support a stream-oriented IFF file writer *******
- X *
- X * These routines will random access back to set a chunk size value when the
- X * caller doesn't know it ahead of time. They'll also do things automatically
- X * like padding and error checking.
- X *
- X * These routines ASSUME they're the only ones writing to the file.
- X * Client should check IFFP error codes. Don't press on after an error!
- X * These routines try to have no side effects in the error case, except that
- X * partial I/O is sometimes unavoidable.
- X *
- X * All of these routines may return DOS_ERROR. In that case, ask DOS for the
- X * specific error code.
- X *
- X * The overall scheme is to open an output GroupContext via OpenWIFF or
- X * OpenWGroup, call either PutCk or {PutCkHdr {IFFWriteBytes}* PutCkEnd} for
- X * each chunk, then use CloseWGroup to close the GroupContext.
- X *
- X * To write a group (LIST, FORM, PROP, or CAT), call StartWGroup, write out
- X * its chunks, then call EndWGroup. StartWGroup automatically writes the
- X * group header and opens a nested context for writing the contents.
- X * EndWGroup closes the nested context and completes the group chunk. */
- X
- X
- X#ifdef FDwAT
- X
- X/* Given a file open for output, open a write context.
- X * The "limit" arg imposes a fence or upper limit on the logical file
- X * position for writing data in this context. Pass in szNotYetKnown to be
- X * bounded only by disk capacity.
- X * ASSUME new context structure allocated by caller but not initialized.
- X * ASSUME caller doesn't deallocate the context before calling CloseWGroup.
- X * The caller is only allowed to write out one FORM, LIST, or CAT in this top
- X * level context (see StartWGroup and PutCkHdr).
- X * CLIENT_ERROR if limit is odd.*/
- Xextern IFFP OpenWIFF(BPTR, GroupContext *, LONG);
- X /* file, new, limit {file position} */
- X
- X/* Start writing a group (presumably LIST, FORM, PROP, or CAT), opening a
- X * nested context. The groupSize includes all nested chunks + the subtype ID.
- X *
- X * The subtype of a LIST or CAT is a hint at the contents' FORM type(s). Pass
- X * in FILLER if it's a mixture of different kinds.
- X *
- X * This writes the chunk header via PutCkHdr, writes the subtype ID via
- X * IFFWriteBytes, and calls OpenWGroup. The caller may then write the nested
- X * chunks and finish by calling EndWGroup.
- X * The OpenWGroup call sets new->clientFrame = parent->clientFrame.
- X *
- X * ASSUME new context structure allocated by caller but not initialized.
- X * ASSUME caller doesn't deallocate the context or access the parent context
- X * before calling CloseWGroup.
- X * ERROR conditions: See PutCkHdr, IFFWriteBytes, OpenWGroup. */
- Xextern IFFP StartWGroup(GroupContext *, ID, LONG, ID, GroupContext *);
- X /* parent, groupType, groupSize, subtype, new */
- X
- X/* End a group started by StartWGroup.
- X * This just calls CloseWGroup and PutCkEnd.
- X * ERROR conditions: See CloseWGroup and PutCkEnd. */
- Xextern IFFP EndWGroup(GroupContext *);
- X /* old */
- X
- X/* Open the remainder of the current chunk as a group write context.
- X * This is normally only called by StartWGroup.
- X *
- X * Any fixed limit to this group chunk or a containing context will impose
- X * a limit on the new context.
- X * This will be called just after the group's subtype ID has been written
- X * so the remaining contents will be a sequence of chunks.
- X * This sets new->clientFrame = parent->clientFrame.
- X * ASSUME new context structure allocated by caller but not initialized.
- X * ASSUME caller doesn't deallocate the context or access the parent context
- X * before calling CloseWGroup.
- X * CLIENT_ERROR if context end is odd or PutCkHdr wasn't called first. */
- Xextern IFFP OpenWGroup(GroupContext *, GroupContext *);
- X /* parent, new */
- X
- X/* Close a write context and update its parent context.
- X * This is normally only called by EndWGroup.
- X *
- X * If this is a top level context (created by OpenWIFF) we'll set the file's
- X * EOF (end of file) but won't close the file.
- X * After calling this, the old context may be deallocated and the parent
- X * context can be accessed again.
- X *
- X * Amiga DOS Note: There's no call to set the EOF. We just position to the
- X * desired end and return. Caller must Close file at that position.
- X * CLIENT_ERROR if PutCkEnd wasn't called first. */
- Xextern IFFP CloseWGroup(GroupContext *);
- X /* old */
- X
- X/* Write a whole chunk to a GroupContext. This writes a chunk header, ckSize
- X * data bytes, and (if needed) a pad byte. It also updates the GroupContext.
- X * CLIENT_ERROR if ckSize == szNotYetKnown. See also PutCkHdr errors. */
- Xextern IFFP PutCk(GroupContext *, ID, LONG, BYTE *);
- X /* context, ckID, ckSize, *data */
- X
- X/* Write just a chunk header. Follow this will any number of calls to
- X * IFFWriteBytes and finish with PutCkEnd.
- X * If you don't yet know how big the chunk is, pass in ckSize = szNotYetKnown,
- X * then PutCkEnd will set the ckSize for you later.
- X * Otherwise, IFFWriteBytes and PutCkEnd will ensure that the specified
- X * number of bytes get written.
- X * CLIENT_ERROR if the chunk would overflow the GroupContext's bound, if
- X * PutCkHdr was previously called without a matching PutCkEnd, if ckSize < 0
- X * (except szNotYetKnown), if you're trying to write something other
- X * than one FORM, LIST, or CAT in a top level (file level) context, or
- X * if ckID <= 0 (these illegal ID values are used for error codes). */
- Xextern IFFP PutCkHdr(GroupContext *, ID, LONG);
- X /* context, ckID, ckSize */
- X
- X/* Write nBytes number of data bytes for the current chunk and update
- X * GroupContext.
- X * CLIENT_ERROR if this would overflow the GroupContext's limit or the
- X * current chunk's ckSize, or if PutCkHdr wasn't called first, or if
- X * nBytes < 0. */
- Xextern IFFP IFFWriteBytes(GroupContext *, BYTE *, LONG);
- X /* context, *data, nBytes */
- X
- X/* Complete the current chunk, write a pad byte if needed, and update
- X * GroupContext.
- X * If current chunk's ckSize = szNotYetKnown, this goes back and sets the
- X * ckSize in the file.
- X * CLIENT_ERROR if PutCkHdr wasn't called first, or if client hasn't
- X * written 'ckSize' number of bytes with IFFWriteBytes. */
- Xextern IFFP PutCkEnd(GroupContext *);
- X /* context */
- X
- X#else /* not FDwAT */
- X
- Xextern IFFP OpenWIFF();
- Xextern IFFP StartWGroup();
- Xextern IFFP EndWGroup();
- Xextern IFFP OpenWGroup();
- Xextern IFFP CloseWGroup();
- Xextern IFFP PutCk();
- Xextern IFFP PutCkHdr();
- Xextern IFFP IFFWriteBytes();
- Xextern IFFP PutCkEnd();
- X
- X#endif /* not FDwAT */
- X
- X#endif IFF_H
- X
- END_OF_FILE
- if test 20481 -ne `wc -c <'src/iff.h'`; then
- echo shar: \"'src/iff.h'\" unpacked with wrong size!
- fi
- # end of 'src/iff.h'
- fi
- if test -f 'src/lighting.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'src/lighting.c'\"
- else
- echo shar: Extracting \"'src/lighting.c'\" \(18901 characters\)
- sed "s/^X//" >'src/lighting.c' <<'END_OF_FILE'
- X/*****************************************************************************
- X*
- X* lighting.c
- X*
- X* from DKBTrace (c) 1990 David Buck
- X*
- X* This module calculates lighting properties like ambient, diffuse, specular,
- X* reflection, refraction, etc.
- X*
- X*
- X* This software is freely distributable. The source and/or object code may be
- X* copied or uploaded to communications services so long as this notice remains
- X* at the top of each file. If any changes are made to the program, you must
- X* clearly indicate in the documentation and in the programs startup message
- X* who it was who made the changes. The documentation should also describe what
- X* those changes were. This software may not be included in whole or in
- X* part into any commercial package without the express written consent of the
- X* author. It may, however, be included in other public domain or freely
- X* distributed software so long as the proper credit for the software is given.
- X*
- X* This software is provided as is without any guarantees or warranty. Although
- X* the author has attempted to find and correct any bugs in the software, he
- X* is not responsible for any damage caused by the use of the software. The
- X* author is under no obligation to provide service, corrections, or upgrades
- X* to this package.
- X*
- X* Despite all the legal stuff above, if you do find bugs, I would like to hear
- X* about them. Also, if you have any comments or questions, you may contact me
- X* at the following address:
- X*
- X* David Buck
- X* 22C Sonnet Cres.
- X* Nepean Ontario
- X* Canada, K2H 8W7
- X*
- X* I can also be reached on the following bulleton boards:
- X*
- X* ATX (613) 526-4141
- X* OMX (613) 731-3419
- X* Mystic (613) 731-0088 or (613) 731-6698
- X*
- X* Fidonet: 1:163/109.9
- X* Internet: David_Buck@Carleton.CA
- X*
- X* IBM Port by Aaron A. Collins. Aaron may be reached on the following BBS'es:
- X*
- X* Lattice BBS (708) 916-1200
- X* The Information Exchange BBS (708) 945-5575
- X* Stillwaters BBS (708) 403-2826
- X*
- X*****************************************************************************/
- X
- X
- X#include "frame.h"
- X#include "vector.h"
- X#include "dkbproto.h"
- X
- Xextern int Trace_Level;
- Xextern FRAME Frame;
- Xextern unsigned long Options;
- Xextern int Quality;
- Xextern long Shadow_Ray_Tests, Shadow_Rays_Succeeded;
- Xextern long Reflected_Rays_Traced, Refracted_Rays_Traced;
- Xextern long Transmitted_Rays_Traced;
- X
- X#define Small_Tolerance 0.001
- X
- Xvoid Colour_At (Colour, Object, Intersection_Point)
- X COLOUR *Colour;
- X OBJECT *Object;
- X VECTOR *Intersection_Point;
- X {
- X register DBL x, y, z;
- X VECTOR Transformed_Point;
- X
- X if (Object -> Object_Texture->Texture_Transformation) {
- X MInverseTransformVector (&Transformed_Point,
- X Intersection_Point,
- X Object -> Object_Texture->Texture_Transformation);
- X }
- X else
- X Transformed_Point = *Intersection_Point;
- X
- X x = Transformed_Point.x;
- X y = Transformed_Point.y;
- X z = Transformed_Point.z;
- X
- X switch (Object -> Object_Texture->Texture_Number) {
- X case BOZO_TEXTURE:
- X Bozo (x, y, z, Object, Colour);
- X break;
- X
- X case MARBLE_TEXTURE:
- X marble (x, y, z, Object, Colour);
- X break;
- X
- X case WOOD_TEXTURE:
- X wood (x, y, z, Object, Colour);
- X break;
- X
- X case CHECKER_TEXTURE:
- X checker (x, y, z, Object, Colour);
- X break;
- X
- X case SPOTTED_TEXTURE:
- X spotted (x, y, z, Object, Colour);
- X break;
- X
- X case AGATE_TEXTURE:
- X agate (x, y, z, Object, Colour);
- X break;
- X
- X case GRANITE_TEXTURE:
- X granite (x, y, z, Object, Colour);
- X break;
- X
- X case GRADIENT_TEXTURE:
- X gradient (x, y, z, Object, Colour);
- X break;
- X
- X case IMAGEMAP_TEXTURE:
- X texture_map (x, y, z, Object, Colour);
- X break;
- X
- X default:
- X *Colour = Object -> Object_Colour;
- X break;
- X }
- X }
- X
- X
- Xvoid Perturb_Normal(New_Normal, Object, Intersection_Point, Surface_Normal)
- X VECTOR *New_Normal, *Intersection_Point, *Surface_Normal;
- X OBJECT *Object;
- X {
- X VECTOR Transformed_Point;
- X register DBL x, y, z;
- X
- X if (Object -> Object_Texture->Bump_Number == NO_BUMPS) {
- X *New_Normal = *Surface_Normal;
- X return;
- X }
- X
- X if (Object -> Object_Texture->Texture_Transformation)
- X MInverseTransformVector (&Transformed_Point,
- X Intersection_Point,
- X Object -> Object_Texture->Texture_Transformation);
- X else
- X Transformed_Point = *Intersection_Point;
- X
- X x = Transformed_Point.x;
- X y = Transformed_Point.y;
- X z = Transformed_Point.z;
- X
- X switch (Object -> Object_Texture->Bump_Number) {
- X case NO_BUMPS: break;
- X
- X case WAVES: waves (x, y, z, Object, New_Normal);
- X break;
- X
- X case RIPPLES: ripples (x, y, z, Object, New_Normal);
- X break;
- X
- X case WRINKLES: wrinkles (x, y, z, Object, New_Normal);
- X break;
- X
- X case BUMPS: bumps (x, y, z, Object, New_Normal);
- X break;
- X
- X case DENTS: dents (x, y, z, Object, New_Normal);
- X break;
- X }
- X return;
- X }
- X
- Xvoid Ambient (Object, Intersection_Point, Surface_Colour, Colour)
- X OBJECT *Object;
- X VECTOR *Intersection_Point;
- X COLOUR *Surface_Colour;
- X COLOUR *Colour;
- X {
- X DBL t;
- X
- X if (Object -> Object_Texture -> Object_Ambient == 0.0)
- X return;
- X
- X t = 1.0 - Surface_Colour->Alpha;
- X Colour->Red += Surface_Colour->Red * t * Object->Object_Texture->Object_Ambient;
- X Colour->Green += Surface_Colour->Green * t * Object->Object_Texture->Object_Ambient;
- X Colour->Blue += Surface_Colour->Blue * t * Object->Object_Texture->Object_Ambient;
- X return;
- X }
- X
- X
- Xvoid Diffuse (Object, Intersection_Point, Eye, Surface_Normal, Surface_Colour, Colour)
- X OBJECT *Object;
- X VECTOR *Intersection_Point, *Surface_Normal;
- X COLOUR *Surface_Colour;
- X COLOUR *Colour;
- X RAY *Eye;
- X {
- X DBL Cos_Angle_Of_Incidence, Halfway_Length, Normal_Length;
- X DBL Intensity, RandomNumber, Light_Source_Depth;
- X RAY Light_Source_Ray;
- X OBJECT *Light_Source, *Blocking_Object;
- X int Intersection_Found;
- X INTERSECTION *Local_Intersection;
- X VECTOR Halfway, REye, Local_Normal, Normal_Projection, Reflect_Direction;
- X COLOUR Light_Colour, Blocking_Colour;
- X PRIOQ *Local_Queue;
- X
- X if ((Object -> Object_Texture -> Object_Diffuse == 0.0) &&
- X (Object -> Object_Texture -> Object_Specular == 0.0) &&
- X (Object -> Object_Texture -> Object_Phong == 0.0))
- X return;
- X
- X if (Object -> Object_Texture -> Object_Specular != 0.0)
- X {
- X REye.x = -Eye->Direction.x;
- X REye.y = -Eye->Direction.y;
- X REye.z = -Eye->Direction.z;
- X }
- X
- X Local_Queue = pq_new (128);
- X
- X for (Light_Source = Frame.Light_Sources ;
- X Light_Source != NULL;
- X Light_Source = Light_Source -> Next_Light_Source)
- X {
- X Intersection_Found = FALSE;
- X Light_Source_Ray.Initial = *Intersection_Point;
- X Light_Source_Ray.Quadric_Constants_Cached = FALSE;
- X Light_Colour = Light_Source->Object_Colour;
- X
- X VSub (Light_Source_Ray.Direction,
- X Light_Source->Object_Center,
- X *Intersection_Point);
- X
- X VLength (Light_Source_Depth, Light_Source_Ray.Direction);
- X
- X VScale (Light_Source_Ray.Direction, Light_Source_Ray.Direction,
- X 1.0/Light_Source_Depth);
- X
- X /* What objects does this ray intersect? */
- X if (Quality > 3)
- X for (Blocking_Object = Frame.Objects ;
- X Blocking_Object != NULL ;
- X Blocking_Object = Blocking_Object -> Next_Object) {
- X
- X Shadow_Ray_Tests++;
- X if (Blocking_Object == Light_Source)
- X continue;
- X
- X for (All_Intersections (Blocking_Object, &Light_Source_Ray, Local_Queue) ;
- X (Local_Intersection = pq_get_highest(Local_Queue)) != NULL ;
- X pq_delete_highest(Local_Queue)) {
- X
- X if ((Local_Intersection -> Depth < Light_Source_Depth-Small_Tolerance)
- X && (Local_Intersection -> Depth > Small_Tolerance))
- X {
- X Shadow_Rays_Succeeded++;
- X if (Blocking_Object->Transparency) {
- X Make_Colour(&Blocking_Colour, 0.0, 0.0, 0.0);
- X Colour_At(&Blocking_Colour, Blocking_Object, &Local_Intersection->Point);
- X Light_Colour.Red *=
- X Blocking_Colour.Red * Blocking_Colour.Alpha;
- X Light_Colour.Green *=
- X Blocking_Colour.Green * Blocking_Colour.Alpha;
- X Light_Colour.Blue *=
- X Blocking_Colour.Blue * Blocking_Colour.Alpha;
- X }
- X else {
- X Intersection_Found = TRUE;
- X break;
- X }
- X }
- X }
- X if (Intersection_Found) {
- X while (pq_get_highest(Local_Queue))
- X pq_delete_highest(Local_Queue);
- X break;
- X }
- X }
- X
- X if (!Intersection_Found)
- X {
- X if (Object->Object_Texture->Object_Phong) /* Phong Specular Highlight rtn. */
- X {
- X VDot(Cos_Angle_Of_Incidence, Eye->Direction, *Surface_Normal);
- X if (Cos_Angle_Of_Incidence < 0.0)
- X {
- X Local_Normal = *Surface_Normal;
- X Cos_Angle_Of_Incidence = -Cos_Angle_Of_Incidence;
- X }
- X else
- X VScale (Local_Normal, *Surface_Normal, -1.0);
- X
- X VScale (Normal_Projection, Local_Normal, Cos_Angle_Of_Incidence);
- X VScale (Normal_Projection, Normal_Projection, 2.0);
- X VAdd (Reflect_Direction, Eye->Direction, Normal_Projection);
- X
- X VDot (Cos_Angle_Of_Incidence, Reflect_Direction, Light_Source_Ray.Direction);
- X VLength (Normal_Length, Light_Source_Ray.Direction);
- X Cos_Angle_Of_Incidence /= Normal_Length;
- X
- X if (Cos_Angle_Of_Incidence < 0.0)
- X Cos_Angle_Of_Incidence = 0;
- X
- X if (Object -> Object_Texture -> Object_PhongSize != 1.0)
- X Intensity = pow(Cos_Angle_Of_Incidence, Object->Object_Texture->Object_PhongSize);
- X else
- X Intensity = Cos_Angle_Of_Incidence;
- X
- X Intensity *= Object -> Object_Texture -> Object_Phong;
- X
- X Colour->Red+=Intensity*(Light_Colour.Red);
- X Colour->Green+=Intensity*(Light_Colour.Green);
- X Colour->Blue+=Intensity*(Light_Colour.Blue);
- X }
- X
- X if (Object->Object_Texture->Object_Specular > 0.0) /* better specular highlights */
- X {
- X VHalf (Halfway, REye, Light_Source_Ray.Direction);
- X VLength (Normal_Length, *Surface_Normal);
- X VLength (Halfway_Length, Halfway);
- X VDot (Cos_Angle_Of_Incidence, Halfway, *Surface_Normal);
- X Cos_Angle_Of_Incidence /= (Normal_Length * Halfway_Length);
- X
- X if (Cos_Angle_Of_Incidence < 0.0)
- X Cos_Angle_Of_Incidence = 0;
- X
- X if (Object -> Object_Texture -> Object_Roughness != 1.0)
- X Intensity = pow(Cos_Angle_Of_Incidence, 1 / Object->Object_Texture->Object_Roughness);
- X else
- X Intensity = Cos_Angle_Of_Incidence;
- X
- X Intensity *= Object->Object_Texture->Object_Specular;
- X
- X Colour->Red+=Intensity* (Light_Colour.Red);
- X Colour->Green+=Intensity* (Light_Colour.Green);
- X Colour->Blue+=Intensity* (Light_Colour.Blue);
- X }
- X
- X if (Object->Object_Texture->Object_Diffuse > 0.0) /* now do normal diffuse */
- X {
- X VDot (Cos_Angle_Of_Incidence, *Surface_Normal, Light_Source_Ray.Direction);
- X if (Cos_Angle_Of_Incidence < 0.0)
- X Cos_Angle_Of_Incidence = -Cos_Angle_Of_Incidence;
- X
- X if (Object -> Object_Texture -> Object_Brilliance != 1.0)
- X Intensity = pow(Cos_Angle_Of_Incidence, Object->Object_Texture->Object_Brilliance);
- X else
- X Intensity = Cos_Angle_Of_Incidence;
- X
- X Intensity *= Object -> Object_Texture -> Object_Diffuse;
- X
- X RandomNumber = (rand()&0x7FFF)/(DBL) 0x7FFF;
- X
- X Intensity -= RandomNumber * Object->Object_Texture->Texture_Randomness;
- X
- X Intensity *= 1.0 - Surface_Colour->Alpha;
- X Colour->Red += Intensity * (Surface_Colour->Red) * (Light_Colour.Red);
- X Colour->Green += Intensity * (Surface_Colour->Green) * (Light_Colour.Green);
- X Colour->Blue += Intensity * (Surface_Colour->Blue) * (Light_Colour.Blue);
- X }
- X }
- X }
- X pq_free (Local_Queue);
- X return;
- X }
- X
- Xvoid Transmit (Object, Intersection_Point, Ray, Surface_Normal, Surface_Colour, Colour)
- X OBJECT *Object;
- X VECTOR *Intersection_Point;
- X RAY *Ray;
- X VECTOR *Surface_Normal;
- X COLOUR *Surface_Colour;
- X COLOUR *Colour;
- X {
- X RAY New_Ray;
- X COLOUR Temp_Colour;
- X
- X if (Surface_Colour->Alpha == 0.0)
- X return;
- X
- X New_Ray.Initial = *Intersection_Point;
- X New_Ray.Direction = Ray->Direction;
- X
- X Copy_Ray_Containers (&New_Ray, Ray);
- X Trace_Level++;
- X Transmitted_Rays_Traced++;
- X Make_Colour (&Temp_Colour, 0.0, 0.0, 0.0);
- X New_Ray.Quadric_Constants_Cached = FALSE;
- X Trace (&New_Ray, &Temp_Colour);
- X Trace_Level--;
- X (Colour -> Red) += Temp_Colour.Red * Surface_Colour->Red * Surface_Colour->Alpha;
- X (Colour -> Green) += Temp_Colour.Green * Surface_Colour->Green * Surface_Colour->Alpha;
- X (Colour -> Blue) += Temp_Colour.Blue * Surface_Colour->Blue * Surface_Colour->Alpha;
- X }
- X
- X
- Xvoid Reflect (Object, Intersection_Point, Ray, Surface_Normal, Colour)
- X OBJECT *Object;
- X VECTOR *Intersection_Point;
- X RAY *Ray;
- X VECTOR *Surface_Normal;
- X COLOUR *Colour;
- X {
- X RAY New_Ray;
- X COLOUR Temp_Colour;
- X VECTOR Local_Normal;
- X VECTOR Normal_Projection;
- X register DBL Normal_Component;
- X
- X if (Object -> Object_Texture -> Object_Reflection != 0.0)
- X {
- X Reflected_Rays_Traced++;
- X VDot (Normal_Component, Ray -> Direction, *Surface_Normal);
- X if (Normal_Component < 0.0) {
- X Local_Normal = *Surface_Normal;
- X Normal_Component *= -1.0;
- X }
- X else
- X VScale (Local_Normal, *Surface_Normal, -1.0);
- X
- X VScale (Normal_Projection, Local_Normal, Normal_Component);
- X VScale (Normal_Projection, Normal_Projection, 2.0);
- X VAdd (New_Ray.Direction, Ray -> Direction, Normal_Projection);
- X New_Ray.Initial = *Intersection_Point;
- X
- X Copy_Ray_Containers (&New_Ray, Ray);
- X Trace_Level++;
- X Make_Colour (&Temp_Colour, 0.0, 0.0, 0.0);
- X New_Ray.Quadric_Constants_Cached = FALSE;
- X Trace (&New_Ray, &Temp_Colour);
- X Trace_Level--;
- X (Colour -> Red) += (Temp_Colour.Red)
- X * (Object -> Object_Texture -> Object_Reflection);
- X (Colour -> Green) += (Temp_Colour.Green)
- X * (Object -> Object_Texture -> Object_Reflection);
- X (Colour -> Blue) += (Temp_Colour.Blue)
- X * (Object -> Object_Texture -> Object_Reflection);
- X }
- X }
- X
- Xvoid Refract (Object, Intersection_Point, Ray, Surface_Normal, Colour)
- X OBJECT *Object;
- X VECTOR *Intersection_Point;
- X RAY *Ray;
- X VECTOR *Surface_Normal;
- X COLOUR *Colour;
- X {
- X RAY New_Ray;
- X COLOUR Temp_Colour;
- X VECTOR Local_Normal;
- X VECTOR Normal_Projection;
- X register DBL Normal_Component, Temp_IOR;
- X
- X if (Object -> Object_Texture -> Object_Refraction != 0.0)
- X {
- X Refracted_Rays_Traced++;
- X VDot (Normal_Component, Ray -> Direction, *Surface_Normal);
- X if (Normal_Component >= 0.0)
- X {
- X VScale (Local_Normal, *Surface_Normal, -1.0);
- X }
- X else
- X {
- X Local_Normal.x = Surface_Normal -> x;
- X Local_Normal.y = Surface_Normal -> y;
- X Local_Normal.z = Surface_Normal -> z;
- X
- X Normal_Component *= -1.0;
- X }
- X
- X VScale (Normal_Projection, Local_Normal, Normal_Component);
- X VAdd (Normal_Projection, Normal_Projection, Ray -> Direction);
- X Copy_Ray_Containers (&New_Ray, Ray);
- X
- X if (Ray -> Containing_Index == -1)
- X {
- X /* The ray is entering from the atmosphere */
- X Ray_Enter (&New_Ray, Object);
- X
- X VScale (Normal_Projection, Normal_Projection,
- X (Frame.Atmosphere_IOR)/(Object -> Object_Texture -> Object_Index_Of_Refraction));
- X }
- X else
- X {
- X /* The ray is currently inside an object */
- X if (New_Ray.Containing_Objects [New_Ray.Containing_Index] == Object)
- X {
- X /* The ray is leaving the current object */
- X Ray_Exit (&New_Ray);
- X if (New_Ray.Containing_Index == -1)
- X /* The ray is leaving into the atmosphere */
- X Temp_IOR = Frame.Atmosphere_IOR;
- X else
- X /* The ray is leaving into another object */
- X Temp_IOR = New_Ray.Containing_IORs [New_Ray.Containing_Index];
- X
- X VScale (Normal_Projection, Normal_Projection,
- X (Object -> Object_Texture -> Object_Index_Of_Refraction) / Temp_IOR);
- X }
- X else
- X {
- X /* The ray is entering a new object */
- X Temp_IOR = New_Ray.Containing_IORs [New_Ray.Containing_Index];
- X Ray_Enter (&New_Ray, Object);
- X
- X VScale (Normal_Projection, Normal_Projection,
- X Temp_IOR/(Object -> Object_Texture -> Object_Index_Of_Refraction));
- X
- X }
- X }
- X
- X VScale (Local_Normal, Local_Normal, -1.0);
- X VAdd (New_Ray.Direction, Local_Normal, Normal_Projection);
- X VNormalize (New_Ray.Direction, New_Ray.Direction);
- X New_Ray.Initial = *Intersection_Point;
- X Trace_Level++;
- X Make_Colour (&Temp_Colour, 0.0, 0.0, 0.0);
- X New_Ray.Quadric_Constants_Cached = FALSE;
- X Trace (&New_Ray, &Temp_Colour);
- X Trace_Level--;
- X (Colour -> Red) += (Temp_Colour.Red)
- X * (Object -> Object_Texture -> Object_Refraction);
- X (Colour -> Green) += (Temp_Colour.Green)
- X * (Object -> Object_Texture -> Object_Refraction);
- X (Colour -> Blue) += (Temp_Colour.Blue)
- X * (Object -> Object_Texture -> Object_Refraction);
- X }
- X }
- X
- Xvoid Fog (Distance, Fog_Colour, Fog_Distance, Colour)
- X DBL Distance, Fog_Distance;
- X COLOUR *Fog_Colour, *Colour;
- X {
- X DBL Fog_Factor, Fog_Factor_Inverse;
- X
- X Fog_Factor = exp(-1.0 * Distance/Fog_Distance);
- X Fog_Factor_Inverse = 1.0 - Fog_Factor;
- X Colour->Red = Colour->Red*Fog_Factor + Fog_Colour->Red*Fog_Factor_Inverse;
- X Colour->Green = Colour->Green*Fog_Factor + Fog_Colour->Green*Fog_Factor_Inverse;
- X Colour->Blue = Colour->Blue*Fog_Factor + Fog_Colour->Blue*Fog_Factor_Inverse;
- X }
- END_OF_FILE
- if test 18901 -ne `wc -c <'src/lighting.c'`; then
- echo shar: \"'src/lighting.c'\" unpacked with wrong size!
- fi
- # end of 'src/lighting.c'
- fi
- echo shar: End of archive 7 \(of 10\).
- cp /dev/null ark7isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 10 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 10 archives.
- rm -f ark[1-9]isdone ark[1-9][0-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
- --
- Mail submissions (sources or binaries) to <amiga@uunet.uu.net>.
- Mail comments to the moderator at <amiga-request@uunet.uu.net>.
- Post requests for sources, and general discussion to comp.sys.amiga.
-